package com.xiyuan.smartutils.client.http;

import com.xiyuan.smartutils.Bytes;
import com.xiyuan.smartutils.StrUtils;
import com.xiyuan.smartutils.Systems;
import com.xiyuan.smartutils.constants.HttpConstants;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

/***
 * HTTP协议中的读取头部行数据
 *
 * @version v1.0.0 @author lgz 2021年1月2日 新建与整理
 */
public class HttpLiner implements HttpConstants {
    public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
    
    // 行列表和读取时的行缓冲
    private final List<String> lineList = new ArrayList<>();
    
    private final byte[] lineBuf = new byte[_DEF_HEADER_LINE_LEN_ * 2];
    private String statusMsg;
    
    private int status = -1;
    /****************************************************************************************************/
    // 解析方法
    /****************************************************************************************************/
    
    /**
     * HTTP的行解析方法
     *
     * @param input
     * @return 返回状态码
     * @throws IOException
     */
    public int parse(InputStream input) throws IOException {
        if (status != _100_CONTINUE_.getCode()) {
            reset();
        }
        
        String firstLine = null;
        int l = -1, pos = 0, status = -1;
        byte[] bf = new byte[1];
        while ((l = input.read(bf)) != -1) {
            if (l == 0) {
                return (status = _100_CONTINUE_.getCode());
            }
            int b = bf[0];
            if (lineList.size() - 1 > _DEF_HEADER_LINE_) {
                // 头部总大小不超过128行最大值
                status = _414_REQUEST_URL_TOO_LARGE_.getCode();
                break;
            }
            
            if (pos > _DEF_HEADER_LINE_LEN_) {
                // 单行总大小不超过8192
                status = _414_REQUEST_URL_TOO_LARGE_.getCode();
                break;
            }
            
            if (b == '\n') {
                
                // 换行
                String line = pos == 0 ? "" : new String(lineBuf, 0, pos, ISO_8859_1);
                
                int len = line == null ? 0 : line.length();
                if (len == 0) {
                    // 头部结束
                    firstLine = list().size() > 0 ? list().get(0) : null;
                    break;
                }
                // 重置
                pos = 0;
                lineList.add(line);
            }
            else if (b != '\r') {
                lineBuf[pos++] = (byte) b;
            }
        }
        
        if (l == -1) {return _82_SERVER_DATA_EXCEPTION_.getCode();}
        if (status != -1) {return status;}
        if (lineList.size() == 0) {return _100_CONTINUE_.getCode();}
        
        int ind = firstLine.indexOf(_ONE_SPACE_);
        if (ind == -1) {
            return _82_SERVER_DATA_EXCEPTION_.getCode();
        }
        
        int ind2 = firstLine.indexOf(_ONE_SPACE_, ind + 1);
        if (ind2 == -1) {
            return _82_SERVER_DATA_EXCEPTION_.getCode();
        }
        
        this.statusMsg = StrUtils.trim(firstLine.substring(ind2));
        
        try {
            status = Integer.parseInt(firstLine.substring(ind + 1, ind2));
            return status;
        }
        catch (Exception e) {
            return _82_SERVER_DATA_EXCEPTION_.getCode();
        }
    }
    
    /****************************************************************************************************/
    // 清理&列表方法
    /****************************************************************************************************/
    
    /**
     * 清理&重置到初始状态
     */
    public void reset() {
        lineList.clear();
        this.statusMsg = null;
        Bytes.fillBytes(lineBuf, 0, (byte) 0, lineBuf.length);
    }
    
    /**
     * 获取解析之后的行列表
     */
    public List<String> list() {
        return lineList;
    }
    
    public String getStatusMsg() {
        return statusMsg;
    }
    
    public int getStatus() {
        return status;
    }
    
    @Override
    public String toString() {
        StringBuilder strb = new StringBuilder();
        for (int i = 0; i < lineList.size(); i++) {
            strb.append(StrUtils.trim(lineList.get(i))).append(Systems.getLineSeparator());
        }
        return strb.toString();
    }
}
